import eventBus from "@/util/eventBus";

const DEBUG = process.env.NODE_ENV !== 'production'
import uuid from 'uuid/v4'

// import logger from "@/components/Marking/util/logger";

import {logger} from 'ricky-util'

export default {
  data () {
    return {
      // alwaysShowMarkTypes: [],
      textLoading: {}
    }
  },
  directives: {
    focus: {
      update (el, binding) {
        if (binding.value) el.focus()
      }
    }
  },
  computed: {
    isDebugger () {
      return this.debugger || DEBUG
    },
    state () {
      return {
        prop: {
          searchBoxShow: this.searchBoxShow,
          scaleType: this.scaleType,
          isClip: this.isClip,
          markShow: this.markShow,
          pointerType: this.pointerType,
          isScrawl: this.isScrawl,
          scrawlType: this.scrawlType,
          scrawlShow: this.scrawlShow,
          brushColor: this.brushColor,
          brushWidth: this.brushWidth,
          searchResultCount: this.searchResultCount,
          seachResultIndex: this.seachResultIndex,
        },
        method: {
          scrawl: this.scrawl,
          exitScrawl: this.exitScrawl,
          setPointerType: this.setPointerType,
          setScrawlType: this.setScrawlType,
          zoomin: this.zoomin,
          zoomout: this.zoomout,
          setScaleType: this.setScaleType,
          reload: this.reload,
          // load: this.load,
          open: this.open,

          showMark: this.showMark,
          hideMark: this.hideMark,
          showScrawl: this.showScrawl,
          hideScrawl: this.hideScrawl,
          rotateCw: this.rotateCw,
          rotateCcw: this.rotateCcw,
          exitClip: this.exitClip,
          clip: this.clip,
          // undo: this.undo,
          // redo: this.redo,
          // setBrushColor: this.setBrushColor,
          // setBrushWidth: this.setBrushWidth,
          toggleSearchBoxShow: this.toggleSearchBoxShow,
          exitSearch: this.exitSearch,
          search: this.search,
          prevSearchResult: this.prevSearchResult,
          nextSearchResult: this.nextSearchResult,

          addMark: this.addMark,
          removeMark: this.removeMark,
          setScrawlData: this.setScrawlData,
          copySelectText: this.copySelectText,
          skipPage: this.skipPage,
          skipByWordPos: this.skipByWordPos,
          getSelection: this.getSelection,
          nextPage: this.nextPage,
          prevPage: this.prevPage,
        }
      }
    },
    logger () {
      return {
        info: this.log,
        error: this.logError
      }
    },
  },
  methods: {
    log () {
      if (this.isDebugger) logger.info(...arguments)
    },
    logError () {
      logger.error(...arguments)
    },
    handleContainerFocus () {
      window.addEventListener('keydown', this.handleWindowKeyDown)
    },
    handleContainerBlur () {
      window.removeEventListener('keydown', this.handleWindowKeyDown)
    },
    handleWindowKeyDown (ev) {
      if (ev.ctrlKey) {
        if (ev.key === 'c') {
          // ev.preventDefault()
          // ev.stopPropagation()
          this.copySelectText()
        } else if (ev.key === 'f') {
          ev.preventDefault()
          ev.stopPropagation()
          this.toggleSearchBoxShow(true)
        }
      }
    },
    getPointerPositionOnStage (ev = event) {
      // let ev = event
      let pos = this.getStage().getPointerPosition()
      if (!ev) return pos

      if (ev.targetTouches) ev = ev.targetTouches[0]

      if (pos) {
        this.dx = ev.screenX - pos.x
        this.dy = ev.screenY - pos.y
      }

      let x = ev.screenX - this.dx
      let y = ev.screenY - this.dy

      if (x < 0) x = 0
      else if (x > this.stageSize.width) x = this.stageSize.width

      if (y < 0) y = 0
      else if (y > this.stageSize.height) y = this.stageSize.height

      return {x, y}
    },
    getPageIndexByPointerPosition (ev) {
      let pointerPositionOnStage = this.getPointerPositionOnStage(ev)
      let currPosition = pointerPositionOnStage.y / this.scale + this.scrollTop
      return Math.floor(currPosition / this.imageSize.height)
    },
    getPointerPositionOnPageGroup (ev, overflow = false) {
      let pointerPositionOnStage = this.getPointerPositionOnStage(ev)

      let pageIndex = this.currPageIndex

      if (!overflow) pageIndex = this.getPageIndexByPointerPosition(ev)

      let tx = pointerPositionOnStage.x - this.stageSize.width / 2
      let ty = pointerPositionOnStage.y

      let cx = -this.scrollLeft
      let cy = -this.scrollTop + this.imageSize.height * pageIndex + this.imageSize.height / 2

      let cr = this.rotation
      if (cr === 90) {
        cx = cy
        cy = this.scrollLeft
      } else if (cr === 180) {
        cy = -cy
      } else if (cr === 270) {
        cx = -cy
        cy = -this.scrollLeft
      }

      cr = cr * Math.PI / 180

      let x = tx * Math.cos(cr) + ty * Math.sin(cr)
      let y = -tx * Math.sin(cr) + ty * Math.cos(cr)

      let position = {
        x: x / this.scale + this.imageSize.width / 2 - cx,
        y: y / this.scale + this.imageSize.height / 2 - cy
      }

      if (position.x < 0) position.x = 0
      else if (position.x > this.imageSize.width) position.x = this.imageSize.width
      if (position.y < 0) position.y = 0
      else if (position.y > this.imageSize.height) position.y = this.imageSize.height

      return position
    },
    getPointerPositionOnImageGroup (ev, overflow = false) {
      let pointerPositionOnPageGroup = this.getPointerPositionOnPageGroup(ev, overflow)

      let pageIndex = this.currPageIndex

      if (!overflow) pageIndex = this.getPageIndexByPointerPosition(ev)

      let imageGroup = this.getStage().findOne(`.imageGroup${pageIndex}`)

      if (!imageGroup) return

      let scale = imageGroup.getAttr('scaleX')

      let pointerPositionOnImageGroup = {
        x: pointerPositionOnPageGroup.x / scale,
        y: pointerPositionOnPageGroup.y / scale
      }

      pointerPositionOnImageGroup.x = pointerPositionOnPageGroup.x / scale - this.imageSize.width / 2 / scale + imageGroup.getAttr('offsetX')
      pointerPositionOnImageGroup.y = pointerPositionOnPageGroup.y / scale - this.imageSize.height / 2 / scale + imageGroup.getAttr('offsetY')

      if (pointerPositionOnImageGroup.x < 0) pointerPositionOnImageGroup.x = 0
      else if (pointerPositionOnImageGroup.x > imageGroup.width()) pointerPositionOnImageGroup.x = imageGroup.width()
      if (pointerPositionOnImageGroup.y < 0) pointerPositionOnImageGroup.y = 0
      else if (pointerPositionOnImageGroup.y > imageGroup.height()) pointerPositionOnImageGroup.y = imageGroup.height()

      return pointerPositionOnImageGroup
    },
    async getWrodsAToB (A, B) {
      if (!A || !B) return
      if (A.pageIndex > B.pageIndex) {
        [A, B] = [B, A]
      } else if (A.pageIndex === B.pageIndex) {
        if (A.index > B.index) {
          [A, B] = [B, A]
        }
      }
      let tRows = {}

      // AB之间的页
      for (let pageIndex = A.pageIndex; pageIndex <= B.pageIndex; pageIndex++) {
        let cache = this.dataList[pageIndex]
        if (!cache) {
          // this.log(cache, i, this.dataList)
          return
        }
        let text = await cache.text()
        let start = 0
        let end = text.words.length - 1
        if (pageIndex === A.pageIndex && pageIndex === B.pageIndex) {
          start = A.index
          end = B.index
        } else if (pageIndex === A.pageIndex) {
          start = A.index
        } else if (pageIndex === B.pageIndex) {
          end = B.index
        }
        for (let index = start; index <= end; index++) {
          let word = text.words[index]

          if (B.pageIndex === A.pageIndex && B.index === A.index) {
            if (A.position && B.position && A.position === B.position) break
          } else {
            if (pageIndex === A.pageIndex && index === A.index) {
              if (A.position === 'right') continue
            }
            if (pageIndex === B.pageIndex && index === B.index) {
              if (B.position === 'left') continue
            }
          }

          let name = `${pageIndex}_${word.rowIndex}`

          // console.log(word)
          if (!tRows[name]) {
            tRows[name] = {
              page: pageIndex,
              x: word.x1,
              y: word.y1,
              width: 0,
              height: 0,
              text: '',
              start: `${pageIndex}-${index}`,
              end: ''
            }
          }
          tRows[name].width = word.x2 - tRows[name].x
          tRows[name].height = word.y2 - tRows[name].y
          tRows[name].text += word.text
          tRows[name].end = `${pageIndex}-${index}`
        }
      }
      return tRows
    },

    async getWordByPointerPosition (ev) {
      let pageIndex = this.getPageIndexByPointerPosition(ev)

      let data = this.dataList[pageIndex]
      if (!data) return
      let text = await data.text()
      if (!text) return
      if (!text.words) return
      if (!text.rows) return

      let pointerPositionOnImageGroup = this.getPointerPositionOnImageGroup(ev)
      if (!pointerPositionOnImageGroup) return

      let prevRowIndex = -1
      let minLineHeight = this.imageSize.height
      for (let i = 0; i < text.words.length; i++) {
        let word = text.words[i]
        //字内
        if (pointerPositionOnImageGroup.x >= word.x1 && pointerPositionOnImageGroup.x <= word.x2 && pointerPositionOnImageGroup.y >= word.y1 && pointerPositionOnImageGroup.y <= word.y2) {
          return {
            position: pointerPositionOnImageGroup.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
            ...word,
            pageIndex: pageIndex,
            index: i
          }
        }
      }
      for (let i = 0; i < text.words.length; i++) {
        let word = text.words[i]
        // 行内
        if (pointerPositionOnImageGroup.y >= word.y1 && pointerPositionOnImageGroup.y <= word.y2) {
          prevRowIndex = word.rowIndex
          break
        } else {
          // 判断最小间隙
          if (prevRowIndex !== word.rowIndex) {
            // 换行了
            if (pointerPositionOnImageGroup.y - word.y2 > 0) {
              // 鼠标上面
              if (pointerPositionOnImageGroup.y - word.y2 < minLineHeight) {
                minLineHeight = pointerPositionOnImageGroup.y - word.y2
                prevRowIndex = word.rowIndex
              }
            } else if (word.y1 - pointerPositionOnImageGroup.y > 0) {
              // 鼠标下面
              if (word.y1 - pointerPositionOnImageGroup.y < minLineHeight) {
                minLineHeight = word.y1 - pointerPositionOnImageGroup.y
                prevRowIndex = word.rowIndex
              }
            }
          }
        }
      }
      // 文字行prevRowIndex
      // let words = text.rows[prevRowIndex] || []

      for (let i = 0; i < text.words.length; i++) {
        let word = text.words[i]
        if (prevRowIndex !== word.rowIndex) continue
        if (pointerPositionOnImageGroup.x < word.x1 && word.wordIndex === 0) {
          // this.log('最左边', word)
          return {
            position: 'left',
            ...word,
            pageIndex: pageIndex,
            index: i
          }
        } else if (pointerPositionOnImageGroup.x > word.x2 && word.wordIndex === text.rows[prevRowIndex].length - 1) {
          // this.log('最右边', word)
          return {
            position: 'right',
            ...word,
            pageIndex: pageIndex,
            index: i
          }
        } else if (pointerPositionOnImageGroup.x >= word.x1 && pointerPositionOnImageGroup.x <= word.x2) {
          // this.log('字上面', word)
          return {
            position: pointerPositionOnImageGroup.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
            ...word,
            pageIndex: pageIndex,
            index: i
          }
        }
      }
    },

    async getWordByIndexPos (pos) {
      if (/^(\d+)-(\d+)$/.test(pos)) {
        let pageIndex = Number(RegExp.$1)
        let index = Number(RegExp.$2)

        let data = this.dataList[pageIndex]

        if (!data) return

        let text = await data.text()
        if (!text) return
        let word = text.words[index]
        if (!word) return
        return {
          ...word,
          pageIndex,
          index
        }
      }
    },
    scrollTo ({x, y}, isRate = false) {
      if (isRate) {
        if (x !== undefined) this.scrollLeft = this.scrollWidth * x
        if (y !== undefined) this.scrollTop = this.scrollHeight * y
      } else {
        if (x !== undefined) this.scrollLeft = x
        if (y !== undefined) this.scrollTop = y
      }
    },
    scrollBy ({x, y}) {
      if (x !== undefined) this.scrollLeft += x
      if (y !== undefined) this.scrollTop += y
    },
    skipPage (pageIndex = 0) {
      this.scrollTo({y: pageIndex * this.imageSize.height})
    },
    async skipByWordPos (start, {behavior = '', block = 'nearest', inline = 'nearest'} = {
      behavior,
      block,
      inline
    }) {
      // console.log(start, end)
      let scrollTop = this.scrollTop
      let scrollLeft = this.scrollLeft
      let startWord = await this.getWordByIndexPos(start)
      // let endWord = await this.getWordByIndexPos(end)
      if (!startWord) return
      // if (endWord.pageIndex - startWord.pageIndex > (this.pageCount + 1) / 2) return this.logger.error('跨度太大')
      // `imageGroup${this.pageIndex}`
      let stage = this.getStage()
      let startImageGroup = stage.findOne(`.imageGroup${startWord.pageIndex}`)
      // let endImageGroup = stage.findOne(`.imageGroup${endWord.pageIndex}`)

      if (!startImageGroup) {
        this.skipPage(startWord.pageIndex)
        await new Promise((resolve, reject) => {
          eventBus.once(`page-loaded-${startWord.pageIndex}`, () => {
            startImageGroup = stage.findOne(`.imageGroup${startWord.pageIndex}`)
            // endImageGroup = stage.findOne(`.imageGroup${endWord.pageIndex}`)
            resolve()
          })
        })
      }

      // console.log(startImageGroup, endImageGroup)

      let startOffetY = (this.imageSize.height - startImageGroup.height() * startImageGroup.scaleY()) / 2
      let startOffetX = (this.imageSize.width - startImageGroup.width() * startImageGroup.scaleX()) / 2
      // let endOffetY = (this.imageSize.height - endImageGroup.height() * endImageGroup.scaleY()) / 2
      // let endOffetX = (this.imageSize.width - endImageGroup.width() * endImageGroup.scaleX()) / 2

      // let tRows = await this.getWrodsAToB(startWord, endWord)

      // let startPage = []
      // let endPage = []
      // for (let key in tRows) {
      //   if (tRows[key].page === startWord.pageIndex) {
      //     startPage.push(tRows[key])
      //   } else if (tRows[key].page === endWord.pageIndex) {
      //     endPage.push(tRows[key])
      //   }
      // }
      // let startMinX = Math.min(...startPage.map(item => item.x)) * startImageGroup.scaleX()
      // let endMinX = Math.min(...endPage.map(item => item.x)) * endImageGroup.scaleX()
      // let startMaxX = Math.max(...startPage.map(item => item.x)) * startImageGroup.scaleX()
      // let endMaxX = Math.max(...endPage.map(item => item.x)) * endImageGroup.scaleX()
      // let minX = Math.min(startMinX, endMinX)
      // let maxX = Math.max(startMaxX, endMaxX)
      //
      // let minY = Math.min(...startPage.map(item => item.y + item.height)) * startImageGroup.scaleY()
      // let maxY = Math.min(...endPage.map(item => item.y + item.height)) * endImageGroup.scaleY()

      let viewHeight = this.stageSize.height / this.scale
      let viewWidth = this.stageSize.width / this.scale

      let minY = Math.min(startWord.y1, startWord.y2) * startImageGroup.scaleY()
      let maxY = Math.max(startWord.y1, startWord.y2) * startImageGroup.scaleY()

      let minX = Math.min(startWord.x1, startWord.x2) * startImageGroup.scaleX()
      let maxX = Math.max(startWord.x1, startWord.x2) * startImageGroup.scaleX()

      // console.log(minX, maxX, viewWidth, (this.imageSize.width - viewWidth) / 2)

      let bottom = startWord.pageIndex * this.imageSize.height + minY + startOffetY //屏幕的下面
      let top = startWord.pageIndex * this.imageSize.height + maxY + startOffetY - viewHeight//屏幕的上面


      let right = -(this.imageSize.width - viewWidth) / 2 + minX + startOffetX //屏幕右边
      let left = -(this.imageSize.width - viewWidth) / 2 + maxX + startOffetX - viewWidth  //屏幕左边

      // console.log('left', left, 'right', right)

      let x = scrollLeft
      if (inline === 'start') {
        x = right
      } else if (inline === 'end') {
        x = left
      } else if (inline === 'center') {
        x = (right + left - maxX + minX) / 2
      } else if (inline === 'nearest') {
        if (scrollLeft <= left || scrollLeft >= right) {
          if (Math.abs(scrollLeft - left) > Math.abs(scrollLeft - right)) {
            x = right
          } else {
            x = left
          }
        }
      }
      // x = left
      // console.log(bottom, top)

      let y = scrollTop
      if (block === 'start') {
        y = bottom
      } else if (block === 'end') {
        y = top
      } else if (block === 'center') {
        y = (bottom + top - maxY + minY) / 2
      } else if (block === 'nearest') {
        if (scrollTop <= top || scrollTop >= bottom) {
          if (Math.abs(scrollTop - top) > Math.abs(scrollTop - bottom)) {
            y = bottom
          } else {
            y = top
          }
        }
      }
      this.scrollTo({x, y})
    },
    nextPage () {
      this.skipPage(this.currPageIndex + 1)
    },
    prevPage () {
      this.skipPage(this.currPageIndex - 1)
    },

    showScrawl () {
      this.scrawlShow = true
    },
    hideScrawl () {
      this.scrawlShow = false
    },
    showMark () {
      this.markShow = true
    },
    hideMark () {
      this.markShow = false
    },
    copySelectText () {
      let selection = this.getSelection()
      let tempEl = document.createElement('textarea')
      tempEl.value = selection ? selection.text : ''
      tempEl.display = 'none'
      document.body.appendChild(tempEl)
      tempEl.select()
      document.execCommand('copy')
      tempEl.parentElement.removeChild(tempEl)
    },
    reload () {
      return this.open(...this.loadArg)
    },
    async getText (item, index) {
      // console.log(item.text)
      // if (item.text) return item.text
      if (this.textLoadFn) {
        if (typeof this.textLoadFn !== 'function') throw new Error('参数 text-load-fn 必须为一个方法')
        if (this.textLoading[index]) {
          // console.log('return')
          return new Promise((resolve, reject) => eventBus.once(`textloaded${index}`, resolve))
        }
        this.textLoading[index] = true
        this.logger.info(`即将开始加载 `, index + 1, ` 页的文字数据`)
        let text = await this.textLoadFn(index, item)
        // item.text = text
        this.logger.info(index + 1, `页的文字数据 加载完成`)
        eventBus.emit(`textloaded${index}`, text)
        this.textLoading[index] = false
        return text
      }
      return item.text
    },
    addMark (mark) {
      mark = JSON.parse(JSON.stringify(mark))
      if (!mark.markid) mark.markid = uuid()
      if (!mark.markline) mark.markline = {}
      if (!mark.config) mark.config = {}
      let index = this.markList.findIndex(item => item.markid === mark.markid)
      if (index > -1) {
        this.markList.splice(index, 1, mark)
      } else {
        this.markList.push(mark)
      }
      // console.log(this.markList)
    },
    zoomin () {
      let scale = this.scale
      if (scale > 2.5) scale += 1
      else if (scale > 1.75) scale += 0.5
      else if (scale > 1.15) scale += 0.25
      else if (scale > 1) scale += 0.15
      else if (scale > 0.75) scale += 0.1
      else scale += 0.05
      this.scaleType = scale
    },
    zoomout () {
      let scale = this.scale
      if (scale > 3) scale -= 1
      else if (scale > 2) scale -= 0.5
      else if (scale > 1.25) scale -= 0.25
      else if (scale > 1.1) scale -= 0.15
      else if (scale > 0.8) scale -= 0.1
      else scale -= 0.05
      this.scaleType = scale
    },
    rotateCw () {
      this.rotation += 90
    },
    rotateCcw () {
      this.rotation -= 90
    },
    setScaleType (scaleType) {
      if (typeof scaleType === 'number') {
        this.scaleType = scaleType
      } else {
        this.scaleType = this.SCALETYPE[scaleType] || this.SCALETYPE.pageFit
      }
    },


  },
  props: {
    alwaysShowMarkTypes: {
      type: Array,
      default: () => {
        return []
      }
    }
  }
}
